/****************************************************************************
* COSC1283/1284 - Programming Techniques
* Semester 1 2011 Assignment #2 - Gloria Jean's Coffee system
* Full Name        : LE YAN
* Student Number   : 3262302
* Yallara Username : s3262302
* Course Code      : BP232
* Program Code     : COSC1284
* Start up code provided by Christopher Hoobin and Xiaodong Li
****************************************************************************/

#include "gjc.h"
#include "gjc_options.h"
#include "gjc_utility.h"

/****************************************************************************
* Function readRestOfLine() is used for buffer clearing.
* Please refer to "test_fgets.c" on Blackboard:
* "Course Documents"->"Function Examples"->"Input Validation Examples"
****************************************************************************/
void 
readRestOfLine()
{
   int c;

   /* Read until the end of the line or end-of-file. */
   while ((c = fgetc(stdin)) != '\n' && c != EOF)
      ;

   /* Clear the error and end-of-file flags. */
   clearerr(stdin);
}


/****************************************************************************
* Initialises the system to a safe empty state.
****************************************************************************/
int 
systemInit(GJCType *menu)
{
  if( menu == NULL )
  {
    fprintf(stderr, "Fatal Error occured\n");
    return FAILURE;
  }
  
  menu->numCategories = 0;
  return SUCCESS;
}


/* get a line of a file */
static int
getline(FILE *file, char **st)
{
  static char tmp[TMP_LEN];
  char c;
  int i = 0;

  if( file == NULL || st == NULL )
  {
    fprintf(stderr, "Cannot get line!\n");
    exit(-1);
  }

  /* read file */
  while( (c = fgetc(file)) != '\n' && c != EOF )
  {
    tmp[i++] = c;     
  }
  tmp[i] = '\0';
  *st = tmp;  
  if( c == EOF )
    return EOF;

  return SUCCESS;
}

/* search category in menu list */
static CategoryTypePtr 
searchcategory(GJCType *menu, char *categoryId)
{ 
  unsigned i;
  CategoryTypePtr current;

  i = 0;
  current = menu->headCategory;
  while( i < menu->numCategories && current != NULL )
  {
    /* if found return the pointer */
    if ( strcmp(categoryId, current->categoryID) == 0 )
    {
       return current;  
    }
    current = current->nextCategory;
    i++;
  }
  return NULL; /*not found*/
}


/* insert item into category */
int
insertitem(GJCType *menu, char *categoryId, ItemTypePtr item)
{
  CategoryTypePtr p;
  ItemTypePtr last, current;
  unsigned i; 

  if( menu == NULL || categoryId == NULL || item == NULL ) 
    return FAILURE;

  /* search category in menu list */
  if( (p = searchcategory(menu, categoryId)) == NULL )
  {
    fprintf(stderr, "invalid categoryId of item: %s\n",
            item->itemName);
    return FAILURE;
  }
 
  
  /* if category is empty */
  if( p->numItems == 0 )
  {
    p->headItem = item;
    p->numItems++;
    return SUCCESS;
  }

  last = NULL;
  current = p->headItem;
  i = 0;
  
  /* traverse the list of item */ 
  while( i<(p->numItems) && 
         (strcmp(item->itemName, current->itemName))>0 )
  {
    last = current;   
    current = current->nextItem;
    i++; 
  }
  
  /* check if itemID is larger than all itemID in the list */
  if( i >= p->numItems )
  {
     last->nextItem = item;   
     p->numItems++;
     return SUCCESS;
  }
  else
  {
     /* check if 'item' will be the first element of the list*/
     if( last != NULL )
     {
       item->nextItem = last->nextItem;
       last->nextItem = item;
     }
     else
     {
       item->nextItem = p->headItem;
       p->headItem = item; 
     }
     p->numItems++;
  }    
  return SUCCESS; 
}

/* delete all items */
void
delete_all_items( CategoryTypePtr category )
{
   ItemTypePtr current, last;

   if( category == NULL )
   {
     fprintf(stderr, "Memory Error!\n");
     exit(FAILURE); 
   }

   last = NULL;
   current = category->headItem;
    
   while( current != NULL )
   {
     last = current;
     current = current->nextItem;
     free(last);
   } 
}

/* free all categories */
void
free_categories( GJCType *menu )
{
  CategoryTypePtr current, last;

  if ( menu == NULL )
  {
    fprintf(stderr,"Menu is empty!\n");
    exit(FAILURE);
  }
 
  last = NULL;
  current = menu->headCategory;
  while( current != NULL )
  {
    delete_all_items( current );
    last = current;  
    current = current->nextCategory;
    free(last);
  }
}

/* delete category */
int 
delete_category( GJCType *menu, char *id)
{
  CategoryTypePtr current, last; 
    
  if( menu == NULL || id == NULL )
  {
    fprintf(stderr, "Memory error!\n");
    exit(FAILURE);
  }
  
  current = menu->headCategory;
  last = NULL;

  while( current != NULL  && strcmp( current->categoryID , id ) != 0)
  {
    last = current;
    current = current->nextCategory; 
  }

  /* if id is not in the linked list */
  if( current == NULL )
   return FAILURE;
  
  /*delete items for the category */
  delete_all_items( current );     
  
  if( last != NULL )
    last->nextCategory = current->nextCategory;
  else
  {
    menu->headCategory = current->nextCategory;  
  }

  printf("Category \"%s - %s\" deleted from the system.\n\n", id, 
          current->categoryName);
  free(current);
  return SUCCESS;
}


/* insert category into menu list */
int 
insertlist(GJCType *menu, CategoryTypePtr category)
{
  CategoryTypePtr current, last;
  unsigned i;

  if ( menu == NULL || category == NULL )
    return FAILURE;

  /* if menu list is empty */
  if( menu->numCategories == 0 )
  {
    menu->headCategory = category;
    menu->numCategories++;
    return SUCCESS;
  }

  /*init for travse*/
  last = NULL; /* last point to the last category just visited */
  current = menu->headCategory; 
  i = 0; 

  /*travse the link list*/
  while( i<(menu->numCategories) && 
         (strcmp(category->categoryName, current->categoryName))>0 )
  {
    last = current;   
    current = current->nextCategory;
    i++; 
  }

  /* check if 'category' larger than all categories in the list */
  if( i >= menu->numCategories )
  {
     last->nextCategory = category;   
     menu->numCategories++;
     return SUCCESS;
  }
  else
  {
     /* check if 'category' will be the first element of the list*/
     if( last != NULL )
     {
       category->nextCategory = last->nextCategory;
       last->nextCategory = category;
     }
     else
     {
       category->nextCategory = menu->headCategory;
       menu->headCategory = category; 
     }
     menu->numCategories++;
     
  }

  return SUCCESS; 
}

/* print item */
void
printitem(CategoryTypePtr category)
{
  ItemTypePtr current;
  unsigned i;
  int j;

  if(category == NULL)
    return;

  i = 0;
  current = category->headItem; 
  while( i<category->numItems && current != NULL )
  { 
      printf("   %s ", current->itemID); 
      printf("%-25s ", current->itemName);

      for( j=0; j<NUM_PRICES; j++ )
      {
        if( current->prices[j].cents >= 10 )
           printf("$%d.%d ", current->prices[j].dollars,
                             current->prices[j].cents);
        else
           printf("$%d.%d0 ", current->prices[j].dollars,
                             current->prices[j].cents);
      }

      printf("\n");
      current = current->nextItem;
      i++;
  }
}


/* print menu */
void
printmenu(GJCType *menu, char categoryType)
{
  
  CategoryTypePtr current;
  unsigned i;

  if ( menu == NULL )
    return;
  
  i = 0;
  current = menu->headCategory;

  while( i<menu->numCategories && current != NULL )
  {
      if( categoryType == current->categoryType )
      {
        printf("%s - ", current->categoryID); 
        printf("%s ", current->categoryName);
        printf("(%d item(s))\n", current->numItems);
        printf("------------------------------------------\n"); 
        printf("   ID    Name                      Small Med   Large\n");
        printf("   ----- ------------------------- ----- ----- -----\n");
        printitem(current);
        printf("\n");
      }

      current = current->nextCategory;
      i++;
  }

}


/****************************************************************************
* Loads all data into the system.
****************************************************************************/
int 
loadData(GJCType *menu, char *menuFile, char *submenuFile)
{
   FILE *Menu, *Submenu;
   char *line, *tmp, *categoryId;
   CategoryTypePtr current;
   ItemTypePtr current_;
   int i;

   if( menu == NULL || menuFile == NULL || submenuFile == NULL )
     return FAILURE;

   Menu = fopen(menuFile, "r");
   Submenu = fopen(submenuFile, "r");
    
   /* Read menuFile */
   while( getline(Menu, &line) != EOF )
   { 
      /* allocate space for current pointer */
      current = (CategoryTypePtr)malloc(sizeof(CategoryType));
      if( current == NULL )
        return FAILURE;
 
      tmp = strtok(line, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current->categoryID, tmp);  

      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      current->categoryType = tmp[0]; 

      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current->categoryName, tmp);

      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current->categoryDescription, tmp);
      
      current->nextCategory = NULL;
      current->headItem = NULL;
      current->numItems = 0;

      /* insert current category to 'menu' list */
      if ( insertlist(menu, current) != SUCCESS )
      {
        fprintf(stderr, "Cannot insert category into menu!\n");
        return FAILURE;
      }

   } 
   fclose(Menu);
   /********** finish to read menufile ***************/
   

   /*********** read submenu file ********************/
   categoryId = (char*)malloc(sizeof(char)*MAX_NAME_LEN);
   if ( categoryId == NULL )
     return FAILURE;

   while( getline(Submenu, &line) != EOF )
   {  
      
      /* allocate space for current pointer */
      current_ = (ItemTypePtr)malloc(sizeof(ItemType));
      
      /* tokenize the line */
      if( current_ == NULL )
        return FAILURE;
     
      tmp = strtok(line, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current_->itemID, tmp);

      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(categoryId, tmp);
      
      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current_->itemName, tmp);
     

      for(i=0; i<NUM_PRICES; i++)
      {
        tmp = strtok(NULL, "|");
          
        if( tmp == NULL )
         return FAILURE;
        current_->prices[i].dollars = atoi(tmp);
        current_->prices[i].cents = ((int)(atof(tmp)*1000.0/10))%100;
       
      }
      
      tmp = strtok(NULL, "|");
      if( tmp == NULL )
        return FAILURE;
      strcpy(current_->itemDescription, tmp);
      /* finish to toknize the line */
     

      current_->nextItem = NULL;
      
      if ( insertitem(menu,categoryId, current_) != SUCCESS)
      {
        fprintf(stderr, "Cannot insert item into a category!\n");
        return FAILURE;
      }

      /* for test 
      printf("%s\n", current_->itemID);
      printf("%s\n", current_->itemName);
      printf("%s\n", categoryId);
      printf("%s\n", current_->itemDescription);
      */
   }

   free(categoryId);
   fclose(Submenu);
   /********* finish to read submenu file **************/

   /*printmenu(menu)*/
   return SUCCESS; 
}


/****************************************************************************
* Deallocates memory used in the program.
****************************************************************************/
void 
systemFree(GJCType *menu)
{
  free_categories(menu);
}
